﻿// --------------------------------------------------------------------------------------------------------------------------------
/**
*   @file           TacViewFile_T.cpp
*   @brief          TacView 文件生成。
*   @details        TacView 文件生成，详见 ACMI 格式说明。
*   @author         GaoYang
*   @date           20181126
*   @version        1.0.0.1
*   @par Copyright
*                   GaoYang
*   @par History
*                   1.0.0.1: GaoYang, 20181126, 首次创建
*                   1.0.0.2: lidaiwei, 20200808, 修正bug
*/

#include "TacViewFile_T.h"

// 跨平台兼容性定义
#if defined(_WIN32) || defined(_WIN64)
	#include <windows.h>
	#define PATH_SEPARATOR '\\'
#else
	#include <unistd.h>
	#define PATH_SEPARATOR '/'
	#define lstrlenA strlen
#endif

using namespace TacView;

// --------------------------------------------------------------------------------------------------------------------------------
/**
*   @name           静态变量。
*   @{
*/
char                            TacViewFile_T::file_str[net_buffer_size];      
/** @}  */

// --------------------------------------------------------------------------------------------------------------------------------
/**
*   @brief          构造函数。
*   @details        构造函数，创建时默认被执行的函数。
*/
TacViewFile_T::TacViewFile_T()
{
	m_file = NULL;
}

// --------------------------------------------------------------------------------------------------------------------------------
/**
*   @brief          析构函数。
*   @details        析构函数，销毁时默认被执行的函数。
*/
TacViewFile_T::~TacViewFile_T()
{
	if (m_file != NULL)
	{
		fclose(m_file);
		m_file = NULL;
	}
}

// --------------------------------------------------------------------------------------------------------------------------------
/**
*   @brief          文件打开函数。
*   @details        文件打开函数。
*   @param[in]      file_name       文件名，包含路径。
*   @param[in]      header          战场基本信息，详见 ACMI 格式说明。
*   @retval         0               正常
*   @retval         1               错误
*   @retval         2               错误 文件打开失败
*/
int TacViewFile_T::Open(
	const char* file_name,
	const Header_T &header)
{
	// 判断是否已经打开
	if (m_file != NULL)
	{
		fclose(m_file);
		m_file = NULL;
	}

	// 生成数据
	BuildString(header, net_buffer_size, file_str);

	// 打开文件，写入数据
#if defined(_WIN32) || defined(_WIN64)
	errno_t err_code = fopen_s(&m_file, file_name, "w+t");
#else
	m_file = fopen(file_name, "w+t");
	int err_code = (m_file == nullptr) ? 1 : 0;
#endif
	if (err_code == 0)
	{
		fwrite(file_str, lstrlenA(file_str), 1, m_file);
	}
	else
	{
		// 文件打开失败
		return 2;
	}

	return 0;
}

/**
*   @brief          是否已经打开文件
*   @retval         0               关闭
*   @retval         1               打开
*/
int TacView::TacViewFile_T::isOpen()
{
	if ( m_file != NULL )
		return 1;
	return 0;
}

// --------------------------------------------------------------------------------------------------------------------------------
/**
*   @brief          文件关闭函数。
*   @details        文件关闭函数。
*   @retval         0               正常
*   @retval         1               错误
*   @retval         2               错误 文件未打开
*/
int TacViewFile_T::Close()
{
	// 判断文件是否打开
	if (m_file == NULL)
	{
		// 文件未打开
		return 2;
	}

	fclose(m_file);
	m_file = NULL;

	//delete[] file_str;
	return 0;
}

// --------------------------------------------------------------------------------------------------------------------------------
/**
*   @brief          在文件中添加记录。
*   @details        在文件中添加记录。
*   @param[in]      state           仿真推进内容，详见 ACMI 格式说明。
*   @retval         0               正常
*   @retval         1               错误
*   @retval         2               错误 文件未打开
*/
int TacViewFile_T::Step(
	const State_T &state)
{
	// 判断文件是否打开
	if (m_file == NULL)
	{
		// 文件未打开
		return 2;
	}

	// 生成数据
	BuildString(state, net_buffer_size, file_str);

	// 写入文件
	fwrite(file_str, lstrlenA(file_str), 1, m_file);

	return 0;
}

int TacViewFile_T::StepRadar(
	const State_T& state)
{
	// 判断文件是否打开
	if ( m_file == NULL )
	{
		// 文件未打开
		return 2;
	}

	// 生成数据
	BuildRadarString(state, net_buffer_size, file_str);

	// 写入文件
	fwrite(file_str, lstrlenA(file_str), 1, m_file);

	return 0;
}

int TacView::TacViewFile_T::AddBoundary(const State_T& state)
{
	if ( m_file == NULL )
		return 2;

	BuildBoundaryString(state, net_buffer_size, file_str);
	fwrite(file_str, lstrlenA(file_str), 1, m_file);
	return 0;
}

int TacViewFile_T::addFrame(double dt)
{
	// 判断文件是否打开
	if ( m_file == NULL )
	{
		// 文件未打开
		return 2;
	}

	// 生成数据
	BuildFrameString(dt, net_buffer_size, file_str);

	// 写入文件
	fwrite(file_str, lstrlenA(file_str), 1, m_file);

	return 0;
}

// --------------------------------------------------------------------------------------------------------------------------------
/**
*   @brief          将战场基本信息转化为 ACMI 格式的字符串。
*   @details        将战场基本信息转化为 ACMI 格式的字符串。
*   @param[in]      header          战场基本信息，详见 ACMI 格式说明。
*   @param[in]      string_length   字符串长度。
*   @param[out]     string          字符串，详见 ACMI 格式说明。
*   @retval         0               正常
*   @retval         1               错误
*/
int TacViewFile_T::BuildString(
	const Header_T &header,
	const int string_length,
	char* string)
{
	// 初始化数据
	memset(string, 0, sizeof(char) * string_length);

	char file_str_line[max_str];
	memset(file_str_line, 0, sizeof(file_str_line));

	// 构建数据内容
	snprintf(file_str_line, sizeof(file_str_line), "FileType=text/acmi/tacview\n");
	safe_strcat(string, sizeof(char) * string_length, file_str_line);
	snprintf(file_str_line, sizeof(file_str_line), "FileVersion=2.2\n");
	safe_strcat(string, sizeof(char) * string_length, file_str_line);
	snprintf(file_str_line, sizeof(file_str_line), "0,ReferenceTime=%s\n", header.reference_time);
	safe_strcat(string, sizeof(char) * string_length, file_str_line);
	snprintf(file_str_line, sizeof(file_str_line), "0,RecordingTime=%s\n", header.recording_time);
	safe_strcat(string, sizeof(char) * string_length, file_str_line);
	return 0;
}

// --------------------------------------------------------------------------------------------------------------------------------
/**
*   @brief          将仿真推进内容转化为 ACMI 格式的字符串。
*   @details        将仿真推进内容转化为 ACMI 格式的字符串。
*   @param[in]      state           仿真推进内容，详见 ACMI 格式说明。
*   @param[in]      string_length   字符串长度。
*   @param[out]     string          字符串，详见 ACMI 格式说明。
*   @retval         0               正常
*   @retval         1               错误
*/
int TacViewFile_T::BuildString(
	const State_T &state,
	const int string_length,
	char* string)
{
	// 初始化数据
	memset(string, 0, sizeof(char) * string_length);

	char file_str_line[max_str];
	memset(file_str_line, 0, sizeof(file_str_line));

	// 构建数据内容
	snprintf(file_str_line, sizeof(file_str_line), "#%.2f\n", state.time);
	safe_strcat(string, sizeof(char) * string_length, file_str_line);
	for (int index = 0; index < state.object_count && index < max_object_tac; index++)
	{
		if ( state.object[index].live == 1 )
		{
			// id
			snprintf(file_str_line, sizeof(file_str_line), "%d,", state.object[index].id);
			safe_strcat(string, sizeof(char) * string_length, file_str_line);

			// 坐标
			if ( state.object[index].coordinate_valid == 1 )
			{
				snprintf(file_str_line, sizeof(file_str_line), "T=%.7f|%.7f|%.2f", state.object[index].coordinate_longitude, state.object[index].coordinate_latitude, state.object[index].coordinate_altitude);
				safe_strcat(string, sizeof(char) * string_length, file_str_line);

				switch ( state.object[index].coordinate_type )
				{
					// LLA
				case 0:
				{
					break;
				}

				// LLAUV
				case 1:
				{
					snprintf(file_str_line, sizeof(file_str_line), "|%.2f|%.2f", state.object[index].coordinate_u, state.object[index].coordinate_v);
					safe_strcat(string, sizeof(char) * string_length, file_str_line);
					break;
				}

				// LLARPY
				case 2:
				{
					snprintf(file_str_line, sizeof(file_str_line), "|%.1f|%.1f|%.1f", state.object[index].coordinate_roll, state.object[index].coordinate_pitch, state.object[index].coordinate_yaw);
					safe_strcat(string, sizeof(char) * string_length, file_str_line);
					break;
				}

				// LLARPYUVH
				case 3:
				{
					snprintf(file_str_line, sizeof(file_str_line), "|%.1f|%.1f|%.1f|%.2f|%.2f|%.2f", state.object[index].coordinate_roll, state.object[index].coordinate_pitch, state.object[index].coordinate_yaw, state.object[index].coordinate_u, state.object[index].coordinate_v, state.object[index].coordinate_heading);
					safe_strcat(string, sizeof(char) * string_length, file_str_line);
					break;
				}

				// 错误
				default:
				{
					break;
				}
				}
			}

			// 基本信息
			if ( state.object[index].base_valid == 1 )
			{
				snprintf(file_str_line, sizeof(file_str_line), ",Name=%s", state.object[index].base_name);
				safe_strcat(string, sizeof(char) * string_length, file_str_line);
				snprintf(file_str_line, sizeof(file_str_line), ",Type=%s", state.object[index].base_type);
				safe_strcat(string, sizeof(char) * string_length, file_str_line);
				snprintf(file_str_line, sizeof(file_str_line), ",Pilot=%s", state.object[index].base_pilot);
				safe_strcat(string, sizeof(char) * string_length, file_str_line);
				snprintf(file_str_line, sizeof(file_str_line), ",Color=%s", state.object[index].base_color);
				safe_strcat(string, sizeof(char) * string_length, file_str_line);
			}


			// 雷达
			if ( state.object[index].radar_valid == 1 )
			{

				snprintf(file_str_line, sizeof(file_str_line), ",RadarMode=%d", state.object[index].radar_mode);
				safe_strcat(string, sizeof(char) * string_length, file_str_line);
				snprintf(file_str_line, sizeof(file_str_line), ",RadarRange=%.2f", state.object[index].radar_range);
				safe_strcat(string, sizeof(char) * string_length, file_str_line);
				snprintf(file_str_line, sizeof(file_str_line), ",RadarHorizontalBeamwidth=%.2f", RADAR_ALL_HBEAMWIDTH_VIEW);
				safe_strcat(string, sizeof(char) * string_length, file_str_line);
				snprintf(file_str_line, sizeof(file_str_line), ",RadarVerticalBeamwidth=%.2f", RADAR_ALL_VBEAMWIDTH_VIEW);
				safe_strcat(string, sizeof(char) * string_length, file_str_line);
				snprintf(file_str_line, sizeof(file_str_line), ",RadarRangeGateAzimuth=%.2f", state.object[index].radar_azimuth);
				safe_strcat(string, sizeof(char) * string_length, file_str_line);
				snprintf(file_str_line, sizeof(file_str_line), ",RadarRangeGateMax=%.2f", state.object[index].radar_range);
				safe_strcat(string, sizeof(char) * string_length, file_str_line);
				snprintf(file_str_line, sizeof(file_str_line), ",RadarRangeGateHorizontalBeamwidth=%.2f", state.object[index].radar_horizontal_beamwidth);
				safe_strcat(string, sizeof(char) * string_length, file_str_line);
				snprintf(file_str_line, sizeof(file_str_line), ",RadarRangeGateVerticalBeamwidth=%.2f", state.object[index].radar_vertical_beamwidth);
				safe_strcat(string, sizeof(char) * string_length, file_str_line);
			}

			// 锁定目标
			if ( state.object[index].locked_target_valid == 1 )
			{
				snprintf(file_str_line, sizeof(file_str_line), ",LockedTarget=%d", state.object[index].locked_target_id);
				safe_strcat(string, sizeof(char) * string_length, file_str_line);
			}

			snprintf(file_str_line, sizeof(file_str_line), "\n");
			safe_strcat(string, sizeof(char) * string_length, file_str_line);
		}
		else
		{
			//id
			snprintf(file_str_line, sizeof(file_str_line), "-%d\n", state.object[index].id);
			safe_strcat(string, sizeof(char) * string_length, file_str_line);
		}
	}

	return 0;
}

int TacViewFile_T::BuildRadarString(
	const State_T& state,
	const int string_length,
	char* string)
{
	// 初始化数据
	memset(string, 0, sizeof(char) * string_length);

	char file_str_line[max_str];
	memset(file_str_line, 0, sizeof(file_str_line));

	// 构建数据内容
	for ( int index = 0; index < state.object_count && index < max_object_tac; index++ )
	{
		if ( state.object[index].live == 1 )
		{
			// id
			snprintf(file_str_line, sizeof(file_str_line), "%d,", state.object[index].id);
			safe_strcat(string, sizeof(char) * string_length, file_str_line);
			// 雷达
			if ( state.object[index].radar_valid == 1 )
			{
				snprintf(file_str_line, sizeof(file_str_line), ",RadarMode=%d", state.object[index].radar_mode);
				safe_strcat(string, sizeof(char) * string_length, file_str_line);
				snprintf(file_str_line, sizeof(file_str_line), ",RadarRange=%.2f", state.object[index].radar_range);
				safe_strcat(string, sizeof(char) * string_length, file_str_line);
				snprintf(file_str_line, sizeof(file_str_line), ",RadarHorizontalBeamwidth=%.2f", RADAR_ALL_HBEAMWIDTH_VIEW);
				safe_strcat(string, sizeof(char) * string_length, file_str_line);
				snprintf(file_str_line, sizeof(file_str_line), ",RadarVerticalBeamwidth=%.2f", RADAR_ALL_VBEAMWIDTH_VIEW);
				safe_strcat(string, sizeof(char) * string_length, file_str_line);
				snprintf(file_str_line, sizeof(file_str_line), ",RadarRangeGateAzimuth=%.2f", state.object[index].radar_azimuth);
				safe_strcat(string, sizeof(char) * string_length, file_str_line);
				snprintf(file_str_line, sizeof(file_str_line), ",RadarRangeGateMax=%.2f", state.object[index].radar_range);
				safe_strcat(string, sizeof(char) * string_length, file_str_line);
				snprintf(file_str_line, sizeof(file_str_line), ",RadarRangeGateHorizontalBeamwidth=%.2f", state.object[index].radar_horizontal_beamwidth);
				safe_strcat(string, sizeof(char) * string_length, file_str_line);
				snprintf(file_str_line, sizeof(file_str_line), ",RadarRangeGateVerticalBeamwidth=%.2f\n", state.object[index].radar_vertical_beamwidth);
				safe_strcat(string, sizeof(char) * string_length, file_str_line);
			}
		}
	}
	return 0;
}

int TacView::TacViewFile_T::BuildBoundaryString(const State_T& state, const int string_length, char* string)
{
	// 初始化数据
	memset(string, 0, sizeof(char) * string_length);

	char file_str_line[max_str];
	memset(file_str_line, 0, sizeof(file_str_line));

	for ( int i = 0; i < max_boundary; i++ )
	{
		snprintf(file_str_line, sizeof(file_str_line), "%ld,T=%f|%f|%f,Type=Navaid+Static+Waypoint,Name=1000 gal Drop Tank,Color=%s\n",
			state.boundaryPoint[i]._id,
			state.boundaryPoint[i]._longitude,
			state.boundaryPoint[i]._latitude,
			state.boundaryPoint[i]._altitude,
			state.boundaryPoint[i]._color
		);
		safe_strcat(string, sizeof(char) * string_length, file_str_line);
	}
	
	snprintf(file_str_line, sizeof(file_str_line), "%ld,LockedTarget=%ld\n", state.boundaryPoint[0]._id, state.boundaryPoint[1]._id);
	safe_strcat(string, sizeof(char) * string_length, file_str_line);

	snprintf(file_str_line, sizeof(file_str_line), "%ld,LockedTarget=%ld\n", state.boundaryPoint[1]._id, state.boundaryPoint[2]._id);
	safe_strcat(string, sizeof(char) * string_length, file_str_line);

	snprintf(file_str_line, sizeof(file_str_line), "%ld,LockedTarget=%ld\n", state.boundaryPoint[2]._id, state.boundaryPoint[3]._id);
	safe_strcat(string, sizeof(char) * string_length, file_str_line);

	snprintf(file_str_line, sizeof(file_str_line), "%ld,LockedTarget=%ld\n", state.boundaryPoint[3]._id, state.boundaryPoint[0]._id);
	safe_strcat(string, sizeof(char) * string_length, file_str_line);

	snprintf(file_str_line, sizeof(file_str_line), "%ld,LockedTarget=%ld\n", state.boundaryPoint[4]._id, state.boundaryPoint[5]._id);
	safe_strcat(string, sizeof(char) * string_length, file_str_line);

	snprintf(file_str_line, sizeof(file_str_line), "%ld,LockedTarget=%ld\n", state.boundaryPoint[5]._id, state.boundaryPoint[6]._id);
	safe_strcat(string, sizeof(char) * string_length, file_str_line);

	snprintf(file_str_line, sizeof(file_str_line), "%ld,LockedTarget=%ld\n", state.boundaryPoint[6]._id, state.boundaryPoint[7]._id);
	safe_strcat(string, sizeof(char) * string_length, file_str_line);

	snprintf(file_str_line, sizeof(file_str_line), "%ld,LockedTarget=%ld\n", state.boundaryPoint[7]._id, state.boundaryPoint[4]._id);
	safe_strcat(string, sizeof(char) * string_length, file_str_line);

	return 0;
}

int TacViewFile_T::BuildFrameString(
	const double dt,
	const int string_length,
	char* string)
{
	// 初始化数据
	memset(string, 0, sizeof(char) * string_length);

	char file_str_line[max_str];
	memset(file_str_line, 0, sizeof(file_str_line));

	// 构建数据内容
	snprintf(file_str_line, sizeof(file_str_line), "#%.3f\n", dt);
	safe_strcat(string, sizeof(char) * string_length, file_str_line);

	return 0;
}